﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LiteratureManage.Domain.DataAccess
{
    using Castle.Facilities.NHibernateIntegration;
    using NHibernate;
    using NHibernate.Criterion;
    using NHibernate.SqlCommand;
    using NHibernate.LambdaExtensions;

    using LiteratureManage.Domain.Models;

    public class LiteratureDao : Dao<int, Literature>, ILiteratureDao
    {
        public LiteratureDao(ISessionManager sessionManager)
            : base(sessionManager)
        {
        }

        public LiteratureDao(ISessionManager sessionManager, string sessionFactoryAlias)
            : base(sessionManager, sessionFactoryAlias)
        {
        }

        public IList<Literature> Search(int pageIndex, int pageSize, LiteratureSearchableTerm searchableTerm, out int total)
        {
            using (var session = OpenSession())
            {
                var criteria = session.CreateCriteria<Literature>();
                if (searchableTerm != null)
                {
                    if (searchableTerm.Literature != null)
                    {
                        criteria.Add(Example.Create(searchableTerm.Literature)
                            .ExcludeProperty("ArticlePublishDate")
                            .ExcludeProperty("CreateDate")
                            .ExcludeZeroes()
                            .EnableLike(MatchMode.Anywhere)
                            );
                    }

                    if (searchableTerm.Author != null)
                    {
                        Author authoralias = null;
                        var authorCriteria = DetachedCriteria<Author>.Create(() => authoralias)
                            .Add(Example.Create(searchableTerm.Author)
                                .ExcludeZeroes()
                                .EnableLike(MatchMode.Anywhere))
                            .SetProjection(LambdaProjection.Property<Author>(a => a.Literature)
                            );

                        criteria.Add(LambdaSubquery.Property<Literature>(literature => literature.Id).In(authorCriteria));
                    }

                    if (searchableTerm.DateInterval != null)
                    {
                        if (searchableTerm.DateInterval.BeginDate != null)
                            criteria.Add<Literature>(literature => literature.ArticlePublishDate >= searchableTerm.DateInterval.BeginDate.Value);

                        if (searchableTerm.DateInterval.EndDate != null)
                            criteria.Add<Literature>(literature => literature.ArticlePublishDate <= searchableTerm.DateInterval.EndDate.Value);
                    }
                }

                var criteriaCount = (ICriteria)criteria.Clone();
                var countValue = criteriaCount.SetProjection(Projections.Count(Projections.Id())).FutureValue<int>();
                var listValue = criteria
                    .AddOrder<Literature>(c => c.Id, Order.Desc)
                    .SetFirstResult((pageIndex - 1) * pageSize)
                    .SetMaxResults(pageSize)
                    .Future<Literature>();

                total = countValue.Value;
                return listValue.ToList();
            }
        }
    }
}
